/*
 * Statistics.h
 *
 *	Mainly used for computing statistical metrics like mean, variance, covariance, correlation etc.,
 *
 *  Created on: Nov 4, 2009
 *      Author: karthik
 */

#ifndef STATISTICS_H_
#define STATISTICS_H_


#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <math.h>

#include "tnt_jama/tnt.h"
#include "tnt_jama/jama_cholesky.h"

using namespace std;
using namespace JAMA;  // JAMA and TNT are defined in namespaces.
using namespace TNT;  // without the "using" statement we would have to write JAMA:: or TNT::
                                         // in front of the functions or fields we are using


using namespace std;

//typedef matrix<double> Matrix;


class Statistics {
public:
	Statistics();
	virtual ~Statistics();
	int t;


	template<class T> static double mean(const vector<T>& );	//	For calculating mean of a vector ( of returns for example )
	template<class T> static double annualVolatility(const vector<T>& );	//	For calculating annualVolatility of a vector ( of returns for example )
	template<class T> static double Covariance(const vector<T>& ,const vector<T>& );	//	For calculating Covariance of one vector of elements with the other.
	template<class T> static double Variance(const vector<T>& );	//	For calculating Variance of elements in a vector.
	template<class T> static double Correlation(const vector<T>& ,const vector<T>& );	//	For calculating Correlation between elements in two vectors.
	template<class T> static Array2D<double> CorrelationMatrix(const vector< vector<T> >& );	//	For calculating Correlation Matrix between every pair of vectors.
	static vector<vector<double> > pricesToReturns(const vector<vector<double> >& );	//	For converting prices to returns using ln(p2/p1).

	//	Calculates mean of an Array2D object. (sum of all elements / n*m )
	static double mean(const Array2D<double>& m){

		int i,j;
		double sum = 0, mu = 0;
		for (i=0; i<m.dim1(); i++)
			for (j=0; j<m.dim2(); j++)
				sum += m[i][j];
		mu = sum / (m.dim1()*m.dim2());
		return mu;
	}

	//	function for reading a text file with a delimiter "," into a vector<vector<string>> object.
//	void static readCSV(std::istream &input, std::vector< std::vector<std::string> > &output)
	void static readCSV(string f_name, std::vector< std::vector<std::string> > &output)
{

			const char *f = f_name.c_str();
			fstream input(f, ios::in);
			if(!input)
			{
				cout << "Error opening the file! Aborting… Make sure the file is kept in the right location....\n ";
				exit(1);
			}

			std::string csvLine;
	        // read every line from the stream
			//std::cout<<"Inside readCSV"<<endl;
	        while( std::getline(input, csvLine) )
	        {
	                std::istringstream csvStream(csvLine);
	                std::vector<std::string> csvColumn;
					std::string csvElement;
	                // read every element from the line that is separated by commas
	                // and put it into the vector or strings
	                while( std::getline(csvStream, csvElement, ',') )
	                {
	                        csvColumn.push_back(csvElement);
	                }
	                output.push_back(csvColumn);
	        }
	}

};

//	For calculating mean of a vector ( of returns for example )
template<class T> double Statistics::mean(const vector<T>& data){
	double sum=0;
	for (int i=0;i<(int) data.size();i++){
		sum+=data[i];
	}
	//std::cout<<"sum :"<<sum<<endl;
	return sum/data.size();
}

//	For calculating annualVolatility of a vector ( of returns for example )
template<class T> double Statistics::annualVolatility(const vector<T>& data){
	double ss=0; // sum of squares
	double mu = mean<T>(data);
	for (int i=0;i<(int) data.size();i++){
		ss+=pow((data[i]-mu),2);
	}
	return sqrt((252*ss)/(data.size()-1));
}

//	For calculating Covariance of one vector of elements with the other.
template<class T> double Statistics::Covariance(const vector<T>& data1,const vector<T>& data2){
	double ss=0; // sum of squares

	double mu1 = mean<T>(data1);
	double mu2 = mean<T>(data2);
	for (int i=0;i<(int) data1.size();i++){
		ss+=(data1[i]-mu1)*(data2[i]-mu2);
	}
	return ss/(data1.size()); // Note: Sample Variance has n-1 in demominator.
}

//	For calculating Variance of elements in a vector.
template<class T> double Statistics::Variance(const vector<T>& data1){
	double ss=0; // sum of squares

	double mu1 = mean<T>(data1);
	for (int i=0;i<(int) data1.size();i++){
		ss+=pow((data1[i]-mu1),2);
	}
	return ss/(data1.size()-1); // Note: Sample Covariance has n in demominator.
}

//	For calculating Correlation between elements in two vectors.
template<class T> double Statistics::Correlation(const vector<T>& data1,const vector<T>& data2){
	int n= data1.size();
	double Sxy = Covariance(data1,data2)*n;
	double sx = pow(Variance(data1),0.5);
	double sy = pow(Variance(data2),0.5);

	return Sxy/((n-1)*sx*sy);
}

//	For calculating Correlation Matrix between every pair of vectors.
template<class T> Array2D<double> Statistics::CorrelationMatrix(const vector< vector<T> >& data){
	int n = data.size();
	Array2D<double> corr(n,n,0.0);
	for (int i=0;i<n;i++){
		corr[i][i]=1;
		for (int j=i+1;j<n;j++){
			corr[i][j]=Correlation(data[i],data[j]);
			corr[j][i]=corr[i][j];
		}
	}
	return corr;
}


#endif /* STATISTICS_H_ */
